/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pa165.machineryrental.dao.impl;

import cz.muni.fi.pa165.machineryrental.dao.RevisionDAO;
import cz.muni.fi.pa165.machineryrental.entities.Customer;
import cz.muni.fi.pa165.machineryrental.entities.Machine;
import cz.muni.fi.pa165.machineryrental.entities.Revision;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * Implementation of RevisionDAO which is used on persisting and other
 * operations on revisions in database.
 *
 * @author David Katuscak, 359273
 */
@Repository
@Component
public class RevisionDAOImpl implements RevisionDAO {

    /**
     * Entity Manager for performing operations on revisions in or from
     * database.
     */
    @PersistenceContext(unitName = "ClassicPU")
    private EntityManager em;

    /**
     * Creates new instance of RevisionDAOImpl on performing operations on
     * entities into or from database.
     *
     * @param em Entity manager running the operations to database.
     */
    public void setEntityManager(EntityManager em) {
        if (em == null) {
            throw new IllegalArgumentException("Given Entity manager cannot be null.");
        }

        this.em = em;
    }

    /**
     * @see cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#getById(long)
     */
    @Override
    public Revision getById(long id) {
        if (id < 0) {
            throw new IllegalArgumentException("ID cannot be negative");
        }

        return em.find(Revision.class, id);
    }

    /**
     * @see
     * cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#create(cz.muni.fi.pa165.machineryrental.entities.Revision)
     */
    @Override
    public void create(Revision revision) {
        if (revision == null) {
            throw new IllegalArgumentException("Revision cannot be null");
        }

        em.persist(revision);
    }

    /**
     * @see
     * cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#update(cz.muni.fi.pa165.machineryrental.entities.Revision)
     */
    @Override
    public void update(Revision revision) {
        if (revision == null) {
            throw new IllegalArgumentException("Revision cannot be null");
        }

        em.merge(revision);
    }

    /**
     * @see
     * cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#remove(cz.muni.fi.pa165.machineryrental.entities.Revision)
     */
    @Override
    public void remove(Revision revision) {
        if (revision == null) {
            throw new DataAccessException("Revision cannot be null") {
            };
        }

        Revision setToFind = em.find(Revision.class, revision.getId());
        if (setToFind == null) {
            throw new PersistenceException("Revision is not in database");
        }
        try {
            em.remove(setToFind);
            em.flush();
        } catch (IllegalArgumentException ex) {
            throw new PersistenceException(ex);
        }
    }

    /**
     * @see cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#findAll()
     */
    @Override
    public List<Revision> findAll() {
        TypedQuery<Revision> query = this.em.createQuery("FROM Revision R", Revision.class);

        return query.getResultList();
    }

    /**
     * @param startDate
     * @param endDate
     * @see
     * cz.muni.fi.pa165.machineryrental.dao.RevisionDAO#findByInterval(java.util.Date,
     * java.util.Date)
     */
    @Override
    public List<Revision> findByInterval(Date startDate, Date endDate) {
        if (startDate == null) {
            throw new IllegalArgumentException("StartDate cannot be null");
        }

        if (endDate == null) {
            throw new IllegalArgumentException("EndDate cannot be null");
        }

        TypedQuery<Revision> query = this.em.createQuery("SELECT r FROM Revision r WHERE r.dateOfRevision BETWEEN :startDate AND :endDate",
                Revision.class).setParameter("startDate", startDate).setParameter("endDate", endDate);

        return query.getResultList();
    }
    
    public List<Revision> findByInterval(Date startDate, Date endDate, Machine machine) {
         if (startDate == null) {
            throw new IllegalArgumentException("StartDate cannot be null");
        }

        if (endDate == null) {
            throw new IllegalArgumentException("EndDate cannot be null");
        }

        TypedQuery<Revision> query = this.em.createQuery("SELECT r FROM Revision r WHERE r.dateOfRevision BETWEEN :startDate AND :endDate AND r.machine = :machine",
                Revision.class).setParameter("startDate", startDate).setParameter("endDate", endDate).setParameter("machine", machine);

        return query.getResultList();
    }

    public List<Revision> findByMachine(Machine machine) {
        if (machine == null) {
            throw new IllegalArgumentException("machine cannot be null");
        }

        TypedQuery<Revision> query = this.em.createQuery("SELECT r FROM Revision r WHERE r.machine = :machine",
                Revision.class).setParameter("machine", machine);

        return query.getResultList();
    }
}
